import pygame
from pygame.locals import *

WINDOW_WIDTH = 500;
WINDOW_HEIGHT = 600;
BACKGROUND_COLOR = (255, 250, 205)
KEY_COLOR = (255,165,0)
LINE_COLOR = (220, 220, 220)
TEXT_SIZE = 32
pygame.init()
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
pygame.display.set_caption("my calculator")

blank = 200
width = 100
space = 5
height = (WINDOW_HEIGHT - blank)//4
key_square = [];
for i in range(0, 4):
    for j in range(0, 4):
        left = j * width
        top = i*height + blank
        rect = pygame.Rect(left, top, width, height)
        key_square.append(rect);
key_clear_rect = pygame.Rect(4*width, blank, width, height*2)
key_equal_rect = pygame.Rect(4*width, blank+height*2, width, height*2)
key_square.append(key_clear_rect)
key_square.append(key_equal_rect)

key_text = ['7', '8', '9', '/',
             '4', '5', '6', 'X',
             '1', '2', '3', '-',
             '.', '0', '<-', '+',
             'C', '=']
text_font = pygame.font.SysFont("arial", TEXT_SIZE)
key_input_array = []
sub_equation = ""
last_val = ""
done = False
result = ""

def get_pressed_key(pos):
    if pos[0] > 0 and pos[0] < 4*width and pos[1] > blank and pos[1] < WINDOW_HEIGHT:
        return key_text[(pos[1]-blank)//height*4 + pos[0]//width]
    elif pos[0] > 4*width and pos[0] < WINDOW_WIDTH and pos[1] > blank and pos[1] < WINDOW_HEIGHT:
        if pos[1] < blank + height*2:
            return key_text[-2]
        else:
            return key_text[-1]

def process_key(key):
    global sub_equation, last_val, done, result
    operator = ['+', '-', 'X', '/']
    digit = [str(d) for d in range(10)]
    length = len(key_input_array)
    if key in operator:
        if last_val not in operator:
            done = False
            if length == 0:
                sub_equation = '0'
                key_input_array.append(0)
            elif last_val[-1] == '.':
                last_val += '0'
            sub_equation += last_val
            last_val = key
            key_input_array.append(last_val)
    elif key in digit:
        if done or length == 0:
            last_val = key
            key_input_array.clear()
            key_input_array.append(int(last_val))
            done = False
        elif last_val in operator:
            sub_equation += last_val
            last_val = key
            key_input_array.append(int(last_val))
        else:
            num = last_val
            if num == '0':
                last_val = key
            else:
                last_val += key
            if num.find('.') == -1:
                key_input_array[length-1] = int(last_val)
            else:
                key_input_array[length-1] = float(last_val)
        calcu()
    elif key == '.':
        if done or length == 0:
            last_val = '0.'
            key_input_array.clear()
            key_input_array.append(float(last_val))
            done = False
        elif last_val in operator:
            sub_equation += last_val
            last_val = '0.'
            key_input_array.append(float(last_val))
        else:
            num = last_val
            if num.find('.') == -1:
                last_val += key
                key_input_array[length-1] = float(last_val)
        calcu()
    elif key == '<-':
        if done == False and length > 0:
            if len(last_val) == 1:
                key_input_array.pop()
                if length == 1:
                    last_val = ''
                else:
                    index = -len(str(key_input_array[-1]))
                    last_val = sub_equation[index:]
                    sub_equation = sub_equation[:index]
            else:
                last_val = last_val[:-1]
                if last_val == '-':
                    last_val = ""
                    result = ""
                    key_input_array.clear()
                else:
                    if last_val.find('.') == -1:
                        key_input_array[-1] = int(last_val)
                    else:
                        key_input_array[-1] = float(last_val)
            calcu()
    elif key == 'C':
        done = False
        key_input_array.clear()
        sub_equation = ""
        last_val = ""
        result = ""
    elif key == '=':
        done = True
        sub_equation = ""
        last_val = result
        key_input_array.clear()
        if len(result) != 0:
            if result.find('.'):
                key_input_array.append(float(result))
            else:
                key_input_array.append(int(result))

def update_equation():
    global sub_equation, last_val, result
    equation = sub_equation + last_val
    equation_length = len(equation)
    total_text = text_font.render(equation, True, (0,0,0))
    rect = total_text.get_rect()
    text_width = int(rect.width)
    line = text_width//(WINDOW_WIDTH-2*space)
    if text_width % (WINDOW_WIDTH-2*space) != 0:
        line += 1
    l = 0
    while l < line:
        if l < line-1:
            equation_text = text_font.render(equation[(l*equation_length+line-1)//line : ((l+1)*equation_length+line-1)//line], True, (0,0,0))
        else:
            equation_text = text_font.render(equation[(l*equation_length+line-1)//line : ], True, (0,0,0))
        rect = equation_text.get_rect()
        rect.centerx = WINDOW_WIDTH - rect.width/2 - space
        rect.centery = blank - (line-l)*(rect.height + space) - rect.height/2 - space
        screen.blit(equation_text, rect)
        l += 1

    if len(result) != 0:
        result_text = text_font.render('='+result, True, (0,0,0))
        rect = result_text.get_rect()
        rect.centerx = WINDOW_WIDTH - rect.width/2 - space
        rect.centery = blank - rect.height/2 - space
        screen.blit(result_text, rect)
        pygame.draw.aaline(screen, LINE_COLOR, (space, blank - rect.height - 2*space), (WINDOW_WIDTH-space, blank - rect.height - 2*space), 1)

def calcu():
    global result
    num = len(key_input_array)
    if num == 0:
        result = ""
    else:
        try:
            ans = key_input_array[0]
            if num <= 2:
                result = str(ans)
            else:
                last_num = [ans]
                last_op = [key_input_array[1], '']
                i = 2
                while i < num:
                    if len(last_num) == 2:
                        if priority(last_op[0], last_op[1]):
                            last_num[0] = opfunc(last_num[0], last_num[1], last_op[0])
                            last_num[1] = key_input_array[i]
                            last_op[0] = last_op[1]
                        else:
                            last_num[1] = opfunc(last_num[1], key_input_array[i], last_op[1])
                    else:
                        last_num.append(key_input_array[i])
                    if i+1 == num:
                        break
                    last_op[1] = key_input_array[i+1]
                    i += 2
                ans = opfunc(last_num[0], last_num[1], last_op[0])
                result = str(ans)
        except:
            result = "NaN"

def priority(op1, op2):
    return op1 == 'X' or op1 == '/' or op2 == '+' or op2 == '-'

def opfunc(num1, num2, op):
    if op == '+':
        return num1 + num2
    elif op == '-':
        return num1 - num2
    elif op == 'X':
        return num1 * num2
    else:
        return num1 / num2
                
while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            exit()
        elif event.type == pygame.MOUSEBUTTONDOWN:
            mouse_pressed = pygame.mouse.get_pressed()
            for i in range(len(mouse_pressed)):
                if mouse_pressed[i]:
                    if i == 0:
                        pos = pygame.mouse.get_pos()
                        key = get_pressed_key(pos)
                        process_key(key)
    screen.fill(BACKGROUND_COLOR)
    for i in range(len(key_square)):
        pygame.draw.rect(screen, KEY_COLOR, key_square[i], 1)
        text = text_font.render(key_text[i], True, (0,0,0))
        rect = text.get_rect()
        rect.center = key_square[i].center
        screen.blit(text, rect)
    update_equation()
    pygame.display.update()
